package com.dingreading.cloud.mall.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.dingreading.cloud.common.util.EnumType;
import com.dingreading.cloud.common.util.NepUtil;
import com.dingreading.cloud.common.util.PageUtil;
import com.dingreading.cloud.mall.dto.UpdateShopCartVo;
import com.dingreading.cloud.mall.entity.ShopCart;
import com.dingreading.cloud.mall.entity.table.ShopCartTableDef;
import com.dingreading.cloud.mall.mapper.ShopCartMapper;
import com.dingreading.cloud.mall.service.ShopCartService;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryCondition;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.BatchArgsSetter;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.update.UpdateChain;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 服务层实现。
 *
 * @author Administrator
 * @since 2023-11-22
 */
@Service
public class ShopCartServiceImpl extends BaseServiceImpl<ShopCartMapper, ShopCart, ShopCartTableDef> implements ShopCartService {

    @Override
    protected ShopCartTableDef getTable() {
        return ShopCartTableDef.shopCart;
    }

    @Resource
    private ShopCartMapper shopCartMapper;


    @Override
    public Page<ShopCart> staffPageListV3(PageUtil pageUtil, String storeUid, String staffUid, String name) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.staffUid.eq(staffUid))
                .and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.code.isNull())
                .and(table.mainComboType.eq(0).or(table.mainComboType.eq(1).and(table.comboType.eq(1))))
                .and(table.type.eq(1));
        if (StringUtils.isNotBlank(name)) {
            condition.and(table.goodsName.like(name)
                    .or(table.code.like(name))
            );
        }

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.id.desc());

        return getMapper().paginate(Page.of(pageUtil.getPage(), pageUtil.getRows()), wrapper);
    }

    @Override
    public int deleteByStaffIdAndCode(String staffUid, String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (staffUid != null)
            condition.and(table.staffUid.eq(staffUid));
        condition.and(table.code.eq(code))
                .and(table.status.notIn(EnumType.ShopCart.PAYED.getType(), EnumType.ShopCart.SEND.getType(), EnumType.ShopCart.REFUND.getType()));
        return getMapper().deleteByCondition(condition);
    }

    @Override
    public List<ShopCart> getByCode(String staffUid, String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (staffUid != null)
            condition.and(table.staffUid.eq(staffUid));
        condition.and(table.code.eq(code));
        return getMapper().selectListByCondition(condition);
    }

    @Override
    public boolean cancelShopCarts(String staffUid, String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (StringUtils.isNotBlank(staffUid))
            condition.and(table.staffUid.eq(staffUid));
        condition.and(table.code.eq(code))
                .and(table.status.in(EnumType.ShopCart.WAIT_CONFIRM.getType(), EnumType.ShopCart.WAIT_PAY.getType()));

        return UpdateChain.of(ShopCart.class)
                .set(table.status, EnumType.ShopCart.CANCEL.getType())
                .set(table.statusName, EnumType.ShopCart.CANCEL.getName())
                .where(condition)
                .update();
    }

    @Override
    public void setOk(String code, String payTimes) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.code.eq(code))
                .and(table.status.in(EnumType.ShopCart.WAIT_CONFIRM.getType(), EnumType.ShopCart.WAIT_PAY.getType()));

        UpdateChain.of(ShopCart.class)
                .set(table.status, EnumType.ShopCart.PAYED.getType())
                .set(table.statusName, EnumType.ShopCart.PAYED.getName())
                .set(table.payTimes, payTimes)
                .where(condition)
                .update();
    }

    @Override
    public int deleteByStaffUidAndIdOrMainShopCartIds(String staffUid, List<Long> ids, List<String> mainShopCartUids) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.staffUid.eq(staffUid))
                .and(table.status.notIn(EnumType.ShopCart.PAYED.getType(), EnumType.ShopCart.SEND.getType(), EnumType.ShopCart.REFUND.getType()));
        if (CollectionUtils.isNotEmpty(mainShopCartUids))
            condition.and(table.id.in(ids).or(table.mainShopCartUid.in(mainShopCartUids)));
        else
            condition.and(table.id.in(ids));
        return getMapper().deleteByCondition(condition);
    }

    @Override
    public List<ShopCart> mainListByStaffUidAndCode(String staffUid, String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.staffUid.eq(staffUid))
                .and(table.code.eq(code))
                .and(table.mainComboType.eq(0).or(table.mainComboType.eq(1).and(table.comboType.eq(1))));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.freeDeliveryStatus.asc(), table.mainComboType.asc(), table.stockOutMethod.asc());

        return getMapper().selectListWithRelationsByQuery(wrapper);
    }

    @Override
    public List<ShopCart> mainListByCodeIn(List<String> codes) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.code.in(codes))
                // 排除组合子商品
                .and(table.mainComboType.eq(0).or(table.mainComboType.eq(1).and(table.comboType.eq(1))));

        return getMapper().selectListByCondition(condition);
    }

    @Override
    public List<ShopCart> mainListAndChildListByCode(String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.code.eq(code));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.id.asc());
        return getMapper().selectListByQuery(wrapper);
    }

    @Override
    public List<ShopCart> childListByStoreUidAndStaffUidAndUid(String storeUid, String staffUid, String mainShopCartUid) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.type.eq(1))
                .and(table.code.isNull())
                .and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.storeUid.eq(storeUid))
                .and(table.staffUid.eq(staffUid))
                .and(table.comboType.eq(0))
                .and(table.mainComboType.eq(1))
                .and(table.mainShopCartUid.eq(mainShopCartUid));

        return getMapper().selectListByCondition(condition);
    }

    @Override
    public List<ShopCart> childListByStoreUidAndStaffUidAndUidsAndCodeIsNull(String storeUid, String staffUid, List<String> mainShopCartUids) {
        QueryCondition condition = table.code.isNull()
                .and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.storeUid.eq(storeUid))
                .and(table.staffUid.eq(staffUid))
                .and(table.comboType.eq(0))
                .and(table.mainComboType.eq(1))
                .and(table.mainShopCartUid.in(mainShopCartUids));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition);
        return getMapper().selectListWithRelationsByQuery(wrapper);
    }

    @Override
    public void updateFormInfo(List<String> shopCartUids, String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.code.isNull())
                .and(table.uid.in(shopCartUids).or(table.mainShopCartUid.in(shopCartUids)));

        UpdateChain.of(ShopCart.class)
                .set(table.code, code)
                .where(condition)
                .update();
    }

    @Override
    public long getStaffShopCartCountV3(String storeUid, String staffUid, int type) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.staffUid.eq(staffUid))
                .and(table.type.eq(type))
                .and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.code.isNull())
                // 排除组合子商品
                .and(table.mainComboType.eq(0).or(table.mainComboType.eq(1).and(table.comboType.eq(1))));

        return getMapper().selectCountByCondition(condition);
    }

    @Override
    public ShopCart getByStaffIdAndGoodsIdAndTypeId(String storeUid, String staffUid, Long goodsId, Long goodsTypeId, Integer mainComboType, Integer comboType) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.staffUid.eq(staffUid))
                .and(table.goodsId.eq(goodsId))
                .and(table.goodsTypeId.eq(goodsTypeId))
                .and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.code.isNull())
                .and(table.type.eq(1))
                .and(table.mainComboType.eq(mainComboType))
                .and(table.comboType.eq(comboType));
        return getMapper().selectOneByCondition(condition);
    }

    @Override
    public int getWaitSendNum(Long goodsTypeId) {
        Integer waitSendNum = shopCartMapper.getWaitSendNum(goodsTypeId);
        return NepUtil.nullToZero(waitSendNum);
    }

    @Override
    public Map<Long, Integer> getWaitSendNum(List<Long> goodsTypeIds) {
        // 结果,默认值设置0
        Map<Long, Integer> map = new HashMap<>();
        for (Long goodsTypeId : goodsTypeIds) {
            map.put(goodsTypeId, 0);
        }
        List<JSONObject> list = shopCartMapper.getWaitSendNumList(goodsTypeIds);
        if (CollectionUtils.isNotEmpty(list)) {
            for (JSONObject jsonObject : list) {
                Long goodsTypeId = jsonObject.getLong("goodsTypeId");
                Integer cnt = jsonObject.getInteger("cnt");
                if (goodsTypeId != null && cnt != null) {
                    map.put(goodsTypeId, NepUtil.nullToZero(cnt));
                }
            }
        }
        return map;
    }

    @Override
    public boolean updateShopCartInfo(
            String staffUid, Long id, Double unitPrice, Double price, Double weight, double totalWeight, Integer num,
            Double originalUnitPrice, Double originalPrice, Double discountRate, double discountPrice
    ) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.id.eq(id))
                .and(table.staffUid.eq(staffUid))
                .and(table.status.in(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.code.isNull());

        return UpdateChain.of(ShopCart.class)
                .set(table.originalUnitPrice, originalUnitPrice)
                .set(table.originalPrice, originalPrice)
                .set(table.unitPrice, unitPrice)
                .set(table.price, price)
                .set(table.discountRate, discountRate)
                .set(table.discountPrice, discountPrice)
                .set(table.weight, weight)
                .set(table.totalWeight, totalWeight)
                .set(table.buyNum, num)
                .where(condition)
                .update();
    }

    @Override
    public List<ShopCart> listRelationByIdIn(List<Long> shopCartIds) {
        QueryWrapper wrapper = QueryWrapper.create()
                .where(table.id.in(shopCartIds))
                .orderBy(table.id.desc());
        return getMapper().selectListWithRelationsByQuery(wrapper);
    }

    @Override
    public List<ShopCart> listRelationByIdInOrderByPrice(List<Long> shopCartIds) {
        QueryWrapper wrapper = QueryWrapper.create()
                .where(table.id.in(shopCartIds))
                .orderBy(table.originalPrice.desc());
        return getMapper().selectListWithRelationsByQuery(wrapper);
    }

    @Override
    public List<ShopCart> myShopCarts(String storeUid, String staffUid) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.staffUid.eq(staffUid))
                .and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.code.isNull())
                .and(table.mainComboType.eq(0).or(table.mainComboType.eq(1).and(table.comboType.eq(1))))
                .and(table.type.eq(1));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.id.desc());

        return getMapper().selectListByQuery(wrapper);
    }

    @Override
    public void dbUpdatePriceInfo(List<UpdateShopCartVo> voList) {
        String sql = "update shop_cart set price=?, deduction_price=?, discount_price=? where uid=?";
        Db.updateBatch(sql, new BatchArgsSetter() {
            @Override
            public int getBatchSize() {
                return voList.size();
            }

            @Override
            public Object[] getSqlArgs(int index) {
                UpdateShopCartVo vo = voList.get(index);
                Object[] args = new Object[4];
                args[0] = vo.getPrice();
                args[1] = vo.getDeductionPrice();
                args[2] = vo.getDiscountPrice();
                args[3] = vo.getUid();
                return args;
            }
        });
    }

    @Override
    public void dbUpdateDeliveryStatus(List<UpdateShopCartVo> voList) {
        String sql = "update shop_cart set free_delivery_id=?, free_delivery_name=?, free_delivery_status=? where uid=?";
        Db.updateBatch(sql, new BatchArgsSetter() {
            @Override
            public int getBatchSize() {
                return voList.size();
            }

            @Override
            public Object[] getSqlArgs(int index) {
                UpdateShopCartVo vo = voList.get(index);
                Object[] args = new Object[4];
                args[0] = vo.getDeliveryId();
                args[1] = vo.getDeliveryName();
                args[2] = vo.getDeliveryStatus();
                args[3] = vo.getUid();
                return args;
            }
        });
    }

}
